"""
创建贪吃蛇游戏窗口 640x480 px
绘制 绿色的蛇🐍，红色苹果🍎 20 px
让蛇运动起来
根据方向键修改朝向

判定碰撞
1. 碰到苹果，吃掉苹果，长身体
2. 碰到墙体，挂了，弹分数框
3. 碰到自己，挂了，弹分数框

基于PyQt5实现
"""


import random
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QKeyEvent, QPaintEvent
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

COLOR_BLACK  = QColor(0,0,0)
COLOR_RED    = QColor(255,0,0)
COLOR_GREEN  = QColor(0,255,0)
BLOCK_SIZE   = 20  #块大小

SCREEN_WIDTH, SCREEN_HEIGHT = 640, 480
BLOCK_SIZE = 20  # 块大小
SCREEN_W = SCREEN_WIDTH // BLOCK_SIZE  # 32
SCREEN_H = SCREEN_HEIGHT // BLOCK_SIZE # 24

DIR_UP   =(0,-1)
DIR_DOWN = (0,1)
DIR_LEFT = (-1,0)
DIR_RIGHT =(1,0)

# 苹果生成区域
map = []
for x in range(0, SCREEN_W):  # 0, 1, 2, 3, 4 .. 31
    for y in range(0, SCREEN_H):  # 0, 1, 2, 3 .. 23
        map.append([x, y])

# 蛇头运动方向
DIR_DICT = {
    Qt.Key_Right : (1,0),
    Qt.Key_Left :  (-1,0),
    Qt.Key_Up :    (0,-1),
    Qt.Key_Down :  (0,1)
    
}

# 蛇头旋转方向字典
ROTATE_DICT = {
    Qt.Key_Right : -90,
    Qt.Key_Left :   90,
    Qt.Key_Up :   180,
    Qt.Key_Down : 0
    
}


class Snake:
    def __init__(self):
        # 蛇   32,24
        self.body = [[10, 5]]

        # 分数
        self.score = 0
        # 方向
        self.direction = Qt.Key_Right
        
        self.head_img = QImage("./img/head-red.png").scaled(BLOCK_SIZE,BLOCK_SIZE)
        self.grow()

    def move(self):
        head_x, head_y = self.body[0]
        dir_x, dir_y = DIR_DICT[self.direction]
        new_head = [head_x + dir_x, head_y + dir_y]
        self.body.insert(0, new_head)
        self.body.pop()

    # 处理按键事件
    def handle(self,event:QKeyEvent):
        if event.key() == Qt.Key_Up and self.direction != Qt.Key_Down:
            self.direction = Qt.Key_Up
        elif event.key() == Qt.Key_Down and self.direction != Qt.Key_Up:
            self.direction = Qt.Key_Down
        elif event.key() == Qt.Key_Left and self.direction != Qt.Key_Right:
            self.direction = Qt.Key_Left
        elif event.key() == Qt.Key_Right and self.direction != Qt.Key_Left:
            self.direction = Qt.Key_Right
    # 生长
    def grow(self):
        tail_x,tail_y = self.body[-1]
        self.body.append([tail_x,tail_y])

    def draw(self,qp:QPainter):
        # 绘制蛇身
        qp.setBrush(COLOR_GREEN)
        for x, y in self.body[1:]:
            qp.drawRect(x * BLOCK_SIZE, y * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE)
        # 绘制蛇头
        head_x,head_y = self.body[0]
        angel = ROTATE_DICT[self.direction]
        rotated_img = self.head_img.transformed(QTransform().rotate(angel))

        qp.drawImage(head_x * BLOCK_SIZE, head_y * BLOCK_SIZE, rotated_img)

class Food:
    def __init__(self,snake:Snake):
        self.pos = self.generate_food(snake)
    
    def generate_food(self,snake:Snake):

        temp_map = [node for node in map if node not in snake.body]
        if not len(temp_map):
            return 
        node  = random.choice(temp_map)
        return node
    def draw(self,qp:QPainter):
        # 绘制食物
        qp.setBrush(QBrush(COLOR_RED))
        qp.drawRect(
            self.pos[0] * BLOCK_SIZE, self.pos[1] * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE
        )

# 创建窗口
class SnakeGame(QMainWindow):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("贪吃蛇")
        #self.resize(640, 480)
        self.setFixedSize(SCREEN_WIDTH, SCREEN_HEIGHT)  # 设置固定窗口大小
        # 创建画画板 QFrame
        self.frame = GameFrame(self)
        # 设置到当前窗口
        self.setCentralWidget(self.frame)


class GameFrame(QFrame):

    def __init__(self, parent: QWidget):
        super().__init__(parent)

        # 自动获取焦点
        self.setFocusPolicy(Qt.StrongFocus)
        # 初始化游戏
        self.init_game()
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.update_game)
        self.timer.start(200)

    def init_game(self):

        # 初始化蛇对象
        self.snake = Snake()
        # food
        self.food = Food(self.snake)

        
       

    def update_game(self):

        self.snake.move()

        # 若蛇头吃到苹果长度+1，分数加一
        head = self.snake.body[0]
        if head == self.food.pos:
            self.food.pos = self.food.generate_food(self.snake)
            self.snake.score += 1
            self.snake.grow()
        
            
        # 判断蛇头是否撞墙
        head_x, head_y = self.snake.body[0]
        if ((head_x>=SCREEN_W or head_x<0)or
            (head_y>=SCREEN_H or head_y<0)or
            self.snake.body[0] in self.snake.body[1:]
            ):
            print("游戏结束")
            QMessageBox.warning(self,"游戏结束",f"得分:{self.snake.score}关闭窗口重启游戏")
            self.init_game()
        # 触发界面刷新
        self.update()

    def keyPressEvent(self, event: QKeyEvent) -> None:
        # print(event.key())
        self.snake.handle(event)

    def paintEvent(self, event: QPaintEvent) -> None:
        painter = QPainter(self)
        # 绘制背景
        painter.setBrush(QBrush(COLOR_BLACK))
        painter.drawRect(self.rect())

        self.snake.draw(painter)

        self.food.draw(painter)


if __name__ == "__main__":

    app = QApplication(sys.argv)
    game = SnakeGame()
    game.show()
    # 让主程序阻塞运行
    sys.exit(app.exec_())
